#include <iostream>
#include <semaphore.h>
#include <pthread.h>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <cassert>

#define MAX_CAP 5

template <class T>
class RingQueue
{
public:
    RingQueue() : m_cap(MAX_CAP), m_ringqueue(m_cap)
    {
        sem_init(&m_ProSem, 0, m_cap);
        sem_init(&m_ConSem, 0, 0);
        pthread_mutex_init(&m_mutex, nullptr);
        m_ProIndex = m_ConIndex = 0;
    }

    ~RingQueue()
    {
        sem_destroy(&m_ProSem);
        sem_destroy(&m_ConSem);
        pthread_mutex_destroy(&m_mutex);
    }

    void Push(const T &data)
    {
        // Push 方法用于将数据放入队列，首先等待可用空间信号量，然后将数据存储在生产者索引位置，最后释放消费者信号量。
        P(m_ProSem);
        pthread_mutex_lock(&m_mutex); // 加锁
        m_ringqueue[m_ProIndex++] = data;
        m_ProIndex %= m_cap;
        pthread_mutex_unlock(&m_mutex); // 解锁
        V(m_ConSem);
    }

    void Pop(T *popnumber)
    {
        // Pop 方法用于从队列中取出数据，首先等待可用数据信号量，然后从消费者索引位置取出数据，最后释放生产者信号量。
        P(m_ConSem);
        pthread_mutex_lock(&m_mutex); // 加锁
        *popnumber = m_ringqueue[m_ConIndex++];
        m_ConIndex %= m_cap;
        pthread_mutex_unlock(&m_mutex); // 解锁
        V(m_ProSem);
    }

private:
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);
    }

    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
    }

    int m_cap;                  // 环形队列的大小
    std::vector<T> m_ringqueue; // 定义环形队列

    pthread_mutex_t m_mutex; // 互斥锁
    sem_t m_ProSem;          // 生产者的信号量
    sem_t m_ConSem;          // 消费者的信号量

    int m_ProIndex; // 生产者在队列中的下标
    int m_ConIndex; // 消费者在队列中的下标
};
